package top.ninwoo.utils.util.impl;

import org.apache.commons.io.FileSystemUtils;
import org.springframework.beans.factory.annotation.Autowired;
import top.ninwoo.utils.util.DockerUtils;
import top.ninwoo.utils.util.OSUtils;
import top.ninwoo.utils.util.Utils;

import java.io.*;
import java.util.*;

/**
 * @Author joliu
 * @Description
 * @Date　Create in 上午10:38 2019/11/4
 */
@Utils
public class OSUtilsImpl implements OSUtils {
    @Autowired
    DockerUtils dockerUtils;

    float TotalBandwidth = 20;
    /**
     * 查看宿主机硬盘资源
     * @return
     */
    @Override
    public int disk() {
        try {
            Long total = FileSystemUtils.freeSpaceKb("/home");
            double disk = (double) total / 1024 / 1024;
            return (int) disk;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }


    @Override
    public int cpuUsage() {
        return cpuUsage(false, "");
    }

    @Override
    public int cpuUsage(String containerId) {
        return cpuUsage(true, containerId);
    }

    /**
     * 功能：获取Linux系统cpu使用率
     * @param inDocker 是否在容器中
     * @param containerId 容器id
     * */
    @Override
    public int cpuUsage(boolean inDocker, String containerId) {
        try {
            Map<?, ?> map1 = inDocker ? cpuinfoInDocker(containerId) : cpuinfo();
            // 这里防止容器不存在，map数组为空
            if(map1.size() == 0) {
                return -1;
            }
            Thread.sleep(5 * 1000);
            Map<?, ?> map2 = inDocker ? cpuinfoInDocker(containerId) : cpuinfo();

            long user1 = Long.parseLong(map1.get("user").toString());
            long nice1 = Long.parseLong(map1.get("nice").toString());
            long system1 = Long.parseLong(map1.get("system").toString());
            long idle1 = Long.parseLong(map1.get("idle").toString());

            long user2 = Long.parseLong(map2.get("user").toString());
            long nice2 = Long.parseLong(map2.get("nice").toString());
            long system2 = Long.parseLong(map2.get("system").toString());
            long idle2 = Long.parseLong(map2.get("idle").toString());

            long total1 = user1 + system1 + nice1;
            long total2 = user2 + system2 + nice2;
            float total = total2 - total1;

            long totalIdle1 = user1 + nice1 + system1 + idle1;
            long totalIdle2 = user2 + nice2 + system2 + idle2;
            float totalidle = totalIdle2 - totalIdle1;

            float cpusage = (total / totalidle) * 100;
            return (int) cpusage;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 内存使用率
     * @return
     */
    @Override
    public int memoryUsage() {
        Map<String, Object> map = new HashMap<String, Object>();
        InputStreamReader inputs = null;
        BufferedReader buffer = null;
        try {
            inputs = new InputStreamReader(new FileInputStream("/proc/meminfo"));
            buffer = new BufferedReader(inputs);
            String line = "";
            while (true) {
                line = buffer.readLine();
                if (line == null) {
                    break;
                }
                int beginIndex = 0;
                int endIndex = line.indexOf(":");
                if (endIndex != -1) {
                    String key = line.substring(beginIndex, endIndex);
                    beginIndex = endIndex + 1;
                    endIndex = line.length();
                    String memory = line.substring(beginIndex, endIndex);
                    String value = memory.replace("kB", "").trim();
                    map.put(key, value);
                }
            }

            long memTotal = Long.parseLong(map.get("MemTotal").toString());
            long memFree = Long.parseLong(map.get("MemFree").toString());
            long memused = memTotal - memFree;
            long buffers = Long.parseLong(map.get("Buffers").toString());
            long cached = Long.parseLong(map.get("Cached").toString());

            double usage = (double) (memused - buffers - cached) / memTotal * 100;
            return (int) usage;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                buffer.close();
                inputs.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return 0;
    }

    @Override
    public int memoryUsage(String containerId) {
        Map<String, Object> map = new HashMap<String, Object>();
        String res = dockerUtils.execInDocker(containerId,"cat /proc/meminfo");
        String[] lines = res.split("\n");
        for (String line : lines) {
            int beginIndex = 0;
            int endIndex = line.indexOf(":");
            if (endIndex != -1) {
                String key = line.substring(beginIndex, endIndex);
                beginIndex = endIndex + 1;
                endIndex = line.length();
                String memory = line.substring(beginIndex, endIndex);
                String value = memory.replace("kB", "").trim();
                map.put(key, value);
            }
        }
        if(map.size() == 0) {
            return 0;
        }
        long memTotal = Long.parseLong(map.get("MemTotal").toString());
        long memFree = Long.parseLong(map.get("MemFree").toString());
        long memused = memTotal - memFree;
        long buffers = Long.parseLong(map.get("Buffers").toString());
        long cached = Long.parseLong(map.get("Cached").toString());

        double usage = (double) (memused - buffers - cached) / memTotal * 100;
        return (int) usage;
    }

    public Map<?, ?> cpuinfoInDocker(String containerId) {
        Map<String, Object> map = new HashMap<String, Object>();
        String res = dockerUtils.execInDocker(containerId, "cat /proc/stat");
        String[] lines = res.split("\n");
        for (int i = 0; i < lines.length; i++) {
            String line = lines[i];
            if (line.startsWith("cpu")) {
                StringTokenizer tokenizer = new StringTokenizer(line);
                List<String> temp = new ArrayList<String>();
                while (tokenizer.hasMoreElements()) {
                    String value = tokenizer.nextToken();
                    temp.add(value);
                }
                map.put("user", temp.get(1));
                map.put("nice", temp.get(2));
                map.put("system", temp.get(3));
                map.put("idle", temp.get(4));
                map.put("iowait", temp.get(5));
                map.put("irq", temp.get(6));
                map.put("softirq", temp.get(7));
                map.put("stealstolen", temp.get(8));
                break;
            }
        }
        return map;
    }



    public Map<?, ?> cpuinfo() {
        InputStreamReader inputs = null;
        BufferedReader buffer = null;
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            inputs = new InputStreamReader(new FileInputStream("/proc/stat"));
            buffer = new BufferedReader(inputs);
            String line = "";
            while (true) {
                line = buffer.readLine();
                if (line == null) {
                    break;
                }
                if (line.startsWith("cpu")) {
                    StringTokenizer tokenizer = new StringTokenizer(line);
                    List<String> temp = new ArrayList<String>();
                    while (tokenizer.hasMoreElements()) {
                        String value = tokenizer.nextToken();
                        temp.add(value);
                    }
                    map.put("user", temp.get(1));
                    map.put("nice", temp.get(2));
                    map.put("system", temp.get(3));
                    map.put("idle", temp.get(4));
                    map.put("iowait", temp.get(5));
                    map.put("irq", temp.get(6));
                    map.put("softirq", temp.get(7));
                    map.put("stealstolen", temp.get(8));
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                buffer.close();
                inputs.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return map;
    }

    /**
     * 查看该主机的网络情况
     * @return
     */
    @Override
    public float networkUsage() {
        // TODO: TOTALBAND需要根据具体情况进行设置
        System.out.println("开始收集带宽率");
        float netUsage = 0.0f;
        Process pro1,pro2;
        Runtime r = Runtime.getRuntime();
        try {
            String command = "cat /proc/net/dev";
            //第一次采集流量数据
            long startTime = System.currentTimeMillis();
            pro1 = r.exec(command);
            BufferedReader in1 = new BufferedReader(new InputStreamReader(pro1.getInputStream()));
            String line = null;
            long inSize1 = 0, outSize1 = 0;
            while((line=in1.readLine()) != null){
                line = line.trim();
                if(line.startsWith("enp6s0")){

                    System.out.println(line);
                    String[] temp = line.split("\\s+");
                    System.out.println("temp: "+temp.length+"temp[0]="+temp[0]);
                    //这里可能因为不同操作系统 展示的结果不同，导致下标不同，
                    //自己对照 cat /proc/net/dev 该指令执行后展示出的结构 找到Receive bytes 是数组里第几个元素，替换下标即可
                    inSize1 = Long.parseLong(temp[1]); //Receive bytes,单位为Byte
                    outSize1 = Long.parseLong(temp[9]);             //Transmit bytes,单位为Byte
                    break;
                }
            }
            in1.close();
            pro1.destroy();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                StringWriter sw = new StringWriter();
                e.printStackTrace(new PrintWriter(sw));
                System.out.println("NetUsage休眠时发生InterruptedException. " + e.getMessage());
                System.out.println(sw.toString());
            }
            //第二次采集流量数据
            long endTime = System.currentTimeMillis();
            pro2 = r.exec(command);
            BufferedReader in2 = new BufferedReader(new InputStreamReader(pro2.getInputStream()));
            long inSize2 = 0 ,outSize2 = 0;
            while((line=in2.readLine()) != null){
                line = line.trim();
                if(line.startsWith("enp6s0")){

                    System.out.println(line);
                    String[] temp = line.split("\\s+");
                    //这里数组下标也需要修改
                    inSize2 = Long.parseLong(temp[1]);
                    outSize2 = Long.parseLong(temp[9]);
                    break;
                }
            }
            if(inSize1 != 0 && outSize1 !=0 && inSize2 != 0 && outSize2 !=0){
                float interval = (float)(endTime - startTime)/1000;
                //网口传输速度,单位为bps
                float curRate = (float)(inSize2 - inSize1 + outSize2 - outSize1)*8/(1000000*interval);
                netUsage = curRate/TotalBandwidth;
                System.out.println("本节点网口速度为: " + curRate + "Mbps");
                System.out.println("本节点网络带宽使用率为: " + netUsage);

            }
            in2.close();
            pro2.destroy();
        } catch (IOException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            System.out.println("NetUsage发生InstantiationException. " + e.getMessage());
            System.out.println(sw.toString());
        }
        return netUsage;
    }
}